﻿using System.Collections.Generic;
using System.Configuration;
using Less.Core.Model;
using Less.Tools;
using PetaPoco;

namespace Less.DAL
{
    // ToDo: Generate IDAL
    public class GenericDAL<T>: IValidate where T : class
    {
        private string tableName = "";
        public virtual string IdName
        {
            get
            {
                string name = ConfigurationManager.AppSettings[string.Format("{0}.IdName", Functions.GetClassName(this))];
                if (name == null)
                    name = "Id";
                return name;
            }
        }
        public virtual string TableName
        {
            get
            {
                if (tableName.IsNullOrEmpty())
                {
                    string name = ConfigurationManager.AppSettings[string.Format("{0}.TableName", Functions.GetClassName(this))];
                    if (name == null)
                        name = GetTableName();
                    tableName = name;
                }
                return tableName;
            }
            set
            {
                tableName = value;
            }
        }
        public IDatabase Database { get; set; }

        public GenericDAL()
        {
            Database = new Database();
            TableName = GetTableName();
        }

        public GenericDAL(string connectionStringName)
        {
            Database = new Database(connectionStringName);
            TableName = GetTableName();
        }

        public GenericDAL(string connectionStringName, string tableName)
        {
            Database = new Database(connectionStringName);
            TableName = tableName;
        }

        public GenericDAL(IDatabase database)
        {
            Database = database;
            TableName = GetTableName();
        }

        public GenericDAL(IDatabase database, string tableName)
        {
            Database = database;
            TableName = tableName;
        }

        public string GetTableName()
        {
            string className = Functions.GetClassName(this);
            string tableName = className.Replace("DAL", "");
            return tableName;
        }

        /// <summary>
        /// Gets all the Records
        /// </summary>
        /// <returns></returns>
        public virtual List<T> SelectAll()
        {
            List<T> list = null;
            list = Database.SelectList<T>(string.Format("SELECT * FROM {0}", TableName));
            return list;
        }

        /// <summary>
        /// Gets all the Records Paged
        /// </summary>
        /// <returns></returns>
        public virtual List<T> SelectPage(int pageIndex, int pageSize, out int totalRecords)
        {
            List<T> list = null;
            totalRecords = 0;
            Page<T> page;
            page = Database.SelectPage<T>(pageIndex, pageSize,string.Format("SELECT * FROM {0}", TableName));
            if (page != null)
            {
                list = page.Items;
                totalRecords = (int) page.TotalItems;
            }
            return list;
        }

        /// <summary>
        /// Gets a  Record 
        /// </summary>
        /// <param name="id">The Id</param>
        /// <returns>The  Record </returns>
        public virtual T SelectById(object id)
        {
            T record = null;
            record = Database.Select<T>(string.Format("SELECT * FROM {0} WHERE {1}=@0", TableName, IdName), id);
            return record;
        }

        /// <summary>
        /// Gets a  Record 
        /// </summary>
        /// <returns>The  Record </returns>
        public virtual T SelectByFieldValue(string fieldName, object value)
        {
            T record = null;
            record = Database.Select<T>(string.Format("SELECT * FROM {0} WHERE {1}=@0", TableName, fieldName), value);
            return record;
        }

        /// <summary>
        /// Gets a  Record 
        /// </summary>
        /// <returns>The  Record </returns>
        public virtual List<T> SelectListByFieldValue(string fieldName, object value)
        {
            List<T> list = null;
            list = Database.SelectList<T>(string.Format("SELECT * FROM {0} WHERE {1}=@0", TableName, fieldName), value);
            return list;
        }

        public virtual List<string> Validate(object record)
        {
            return new List<string>();
        }

        /// <summary>
        /// Inserts a User Record 
        /// </summary>
        /// <param name="record">The User Record</param>
        public virtual object Insert(T record)
        {
            List<string> faults = Validate(record);
            if (faults.IsNullOrEmpty())
                return Database.Insert(TableName, record);
            else
                throw new ValidationException(faults);
        }

        /// <summary>
        /// Updates a User Record 
        /// </summary>
        /// <param name="record">The User Record</param>
        public virtual int Update(T record)
        {
            List<string> faults = Validate(record);
            if ( faults.IsNullOrEmpty() )
                return Database.Update(TableName, record);
            else
                throw new ValidationException(faults);
        }

        /// <summary>
        /// Deletes a User Record 
        ///  </summary>
        /// <param name="record">The User Record and its associated Entity Record</param>
        public virtual int Delete(T record)
        {
            return Database.Delete(TableName, record);
        }


        /// <summary>
        /// Inserts a User Record 
        /// </summary>
        /// <param name="record">The User Record</param>
        public virtual object Save(T record)
        {
            var iid = record as IId;
            if (iid!=null)
            {
            	if (iid.Id>0)
                {
                    return Update(record);
                }
                else
                {
                    return Insert(record);
                }
            }
            else
            {
                return Insert(record);
            }
        }
    }
}